package com.shark.uh.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.shark.uh.enums.CaptchaSendMethod;
import com.shark.uh.enums.ResponseCode;
import com.shark.uh.enums.UserStatus;
import com.shark.uh.enums.UserTableFields;
import com.shark.uh.model.entity.UserInfo;
import com.shark.uh.model.vo.UserVO;
import com.shark.uh.model.dto.user.UserBindDTO;
import com.shark.uh.model.dto.user.UserUpdateDTO;
import com.shark.uh.exception.BusinessException;
import com.shark.uh.service.VerificationCodeService;
import com.shark.uh.utils.ValidationUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shark.uh.model.entity.User;
import com.shark.uh.service.UserService;
import com.shark.uh.mapper.UserMapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;


/**
 *
 */
@Log4j2
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource(name = "emailVerificationCodeServiceImpl")
    private VerificationCodeService emailVerificationCodeService;


    /**
     * @param userId
     * @return
     */
    @Override
    public UserInfo getUserInfoById(Long userId) {
        User user = this.getById(userId);
        String userInfos = user.getInfos();
        return JSON.parseObject(userInfos, UserInfo.class);
    }

    @Override
    public void updateUser(UserUpdateDTO request) {
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        long id = StpUtil.getLoginIdAsLong();
        userUpdateWrapper
                .eq("id", id)
                .set(request.getAge() != null, "age", request.getAge())
                .set(StringUtils.isNotBlank(request.getNickname()), "nickname", request.getNickname())
                .set(StringUtils.isNotBlank(request.getGender()), "gender", request.getGender())
                .set(StringUtils.isNotBlank(request.getProfession()), "profession", request.getProfession())
                .set(StringUtils.isNotBlank(request.getEducation()), "education", request.getEducation())
                .set(StringUtils.isNotBlank(request.getRemark()), "remark", request.getRemark());
        this.update(userUpdateWrapper);
    }

    @Override
    public UserVO getUserInfo() {
        User user = this.getById(StpUtil.getLoginIdAsLong());
        return new UserVO(user);
    }

    @Override
    public void bind(UserBindDTO request) {
        this.beforeBindCheck(request);
        // 更新联系方式
        long id = StpUtil.getLoginIdAsLong();
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.eq(UserTableFields.ID.getFieldName(), id).set(request.getType(), request.getDetails());
        this.update(userUpdateWrapper);
    }

    @Override
    public void unbind(UserBindDTO request) {

        // 参数校验
        this.checkBindRequest(request);

        // 获取登录用户信息
        long id = StpUtil.getLoginIdAsLong();
        User user = this.getById(id);

        // 检查是否已绑定电话
        if (request.getType().equals(UserTableFields.PHONE.getFieldName()) && request.getDetails().equals(user.getPhone())) {
            // 如果没绑定电话，直接返回
            if (StringUtils.isBlank(user.getPhone())) {
                return;
            }
            log.info("解绑手机号不符合输入");
            throw new BusinessException(ResponseCode.INVALID_PARAMETER);
        }

        // 检查是否已绑定邮箱
        if (request.getType().equals(UserTableFields.EMAIL.getFieldName()) && request.getDetails().equals(user.getEmail())) {
            // 如果没绑定，直接返回
            if (StringUtils.isBlank(user.getEmail())) {
                return;
            }
            log.info("解绑邮箱不符合输入");
            throw new BusinessException(ResponseCode.INVALID_PARAMETER);
        }

        // 验证码校验
        emailVerificationCodeService.verify(request.getDetails(), request.getCode());

        // 清空联系方式
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.eq(UserTableFields.ID.getFieldName(), id).set(request.getType(), StringUtils.EMPTY);
        this.update(userUpdateWrapper);
    }

    /**
     * @param email
     * @return
     */
    @Override
    public int countByEmail(String email) {
        return userMapper.countByEmail(email);
    }

    /**
     * @param email
     * @return
     */
    @Override
    public int activeUser(String email) {
        return userMapper.setStatus(email, UserStatus.ACTIVE.getStatus());
    }

    private void checkBindRequest(UserBindDTO request) {
        // 空白校验
        if (StringUtils.isAnyBlank(request.getType(), request.getDetails(), request.getCode())) {
            log.info("缺少必要参数");
            throw new BusinessException(ResponseCode.INVALID_PARAMETER);
        }

        if (request.getType().equals(CaptchaSendMethod.PHONE.getMethod())) {
            if (!ValidationUtils.isValidPhoneNumber(request.getDetails())) {
                log.info("手机号码不符合格式");
                throw new BusinessException(ResponseCode.INVALID_PARAMETER);
            }
        }

        if (request.getType().equals(CaptchaSendMethod.EMAIL.getMethod())) {
            if (!ValidationUtils.isValidEmail(request.getDetails())) {
                log.info("邮箱号码不符合格式");
                throw new BusinessException(ResponseCode.INVALID_PARAMETER);
            }
        }

    }

    private void beforeBindCheck(UserBindDTO request) {
        this.checkBindRequest(request);
        if (request.getType().equals(CaptchaSendMethod.PHONE.getMethod())) {
            if (phoneHasBindByAllUsers(request.getDetails()) || loginUserHasBindPhone(request.getDetails())) {
                throw new BusinessException(ResponseCode.INVALID_PARAMETER);
            }
        }
        if (request.getType().equals(CaptchaSendMethod.EMAIL.getMethod())) {
            if (emailHasBindByAllUsers(request.getDetails()) || loginUserHasBindEmail(request.getDetails())) {
                throw new BusinessException(ResponseCode.INVALID_PARAMETER);
            }
        }
        emailVerificationCodeService.verify(request.getDetails(), request.getCode());

    }

    private boolean phoneHasBindByAllUsers(String phone) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq(UserTableFields.PHONE.getFieldName(), phone);
        Integer count = this.userMapper.selectCount(userQueryWrapper);
        return count > 0;
    }

    private boolean loginUserHasBindPhone(String phone) {
        long userId = StpUtil.getLoginIdAsLong();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq(UserTableFields.ID.getFieldName(), userId).eq(UserTableFields.PHONE.getFieldName(), phone);
        Integer count = this.userMapper.selectCount(userQueryWrapper);
        return count > 0;
    }

    private boolean loginUserHasBindEmail(String email) {
        long userId = StpUtil.getLoginIdAsLong();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq(UserTableFields.ID.getFieldName(), userId).eq(UserTableFields.EMAIL.getFieldName(), email);
        Integer count = this.userMapper.selectCount(userQueryWrapper);
        return count > 0;
    }

    private boolean emailHasBindByAllUsers(String email) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq(UserTableFields.EMAIL.getFieldName(), email);
        Integer count = this.userMapper.selectCount(userQueryWrapper);
        return count > 0;
    }


}




